#ifndef __MISC_LIB_SRC_
#define __MISC_LIB_SRC_

#include "misclib.h"
#include "model.h"
#include <malloc.h>
#include <stdarg.h>

using namespace std;
using namespace mup;
#ifdef DEBUG
/* ------------------------------------------------------------------------- */
void call_debug_trap()
{
    model_class & mo = getModel();
    return;
}
#endif
/* ------------------------------------------------------------------------- */
bool src_matchkeyword_aux(const string & keyword, ... ){
    va_list ap;
    int counter = 0;
    va_start(ap, keyword);
    while( true ) {
        const char * strn = va_arg(ap, const char *);
        if( strn == NULL ) return false;
        if( keyword == strn ) return true;
        if( counter > 50 ) fatal_stop("Function 'matchkeyword_aux' was improperly constructed. Loop appears to be continuous.\n");
        counter++;
    }
};
/* ------------------------------------------------------------------------- */
int stdsprintf(string & dest, const char * fmt, ...){
    const int bufrsize = 5000;
    char bufr[bufrsize];
    va_list args;
    va_start(args, fmt);
    int num = vsprintf(bufr, fmt, args);
    rassert( num < bufrsize - 1 );
    dest.assign( bufr );
    return num;
}
/* ------------------------------------------------------------------------- */
int stdvsprintf(string & dest, const char * fmt, va_list args){
    const int bufrsize = 5000;
    char bufr[bufrsize];
    int num = vsprintf(bufr, fmt, args);
    rassert( num < bufrsize - 1 );
    dest.assign( bufr );
    return num;
}
/* ------------------------------------------------------------------------- */
void throw_uncaught_exception(const char * msg, const char * funcname, const char * fname, int line_number){
    fprintf(stderr, "Msg: %s\n", msg);
    fprintf(stderr, "Uncaught exception generated in function: '%s'\n", funcname);
    fprintf(stderr, "Process requested termination @ %s:%i\n", fname, line_number);
    terminate();
};
/* ------------------------------------------------------------------------- */
const string & return_string(){
    static string s;
    return s;
}
/* ------------------------------------------------------------------------- */
bool breakpoint(){
    // breakpoint called
    return true;
}
/* ------------------------------------------------------------------------- */
float convertstring2float(const string & str){
    if( ! isStringReal(str.c_str())) return static_cast<float>(sqrt(-1));
    float rvalue = 0;
    sscanf(str.c_str(),"%f", &rvalue);
    return rvalue;
};
/* ------------------------------------------------------------------------- */
int convertstring2integer(const string & str){
    if( ! isStringInteger(str.c_str())) return static_cast<int>(sqrt(-1));
    int rvalue = 0;
    sscanf(str.c_str(),"%i", &rvalue);
    return rvalue;
};
/* ------------------------------------------------------------------------- */
string convertfloat2string(const float & fval){
    string dest;
    stdsprintf(dest, "%g", fval);
    return dest;
};
/* ------------------------------------------------------------------------- */
string converthandle2string(const int & handle){
    string dest;
    stdsprintf(dest, "file@%x", static_cast<unsigned int>(handle) );
    return dest;
};
/* ------------------------------------------------------------------------- */
string convertcomplex2string(const qgcomplex & cval){
    string dest;
    stdsprintf(dest, "%g + i*(%g)", cval.real(), cval.imag() );
    return dest;
};
/* ------------------------------------------------------------------------- */
string removequotes(const string & str){
    return str.substr(1, str.size()-2);
}
/* ------------------------------------------------------------------------- */
bool isStringString(const char * str){
    if(strlen(str) < 2) return false;
    if(str[0] == '\"' && str[strlen(str)-1] == '\"'){
        return true;
    }
    return false;
}
/* ------------------------------------------------------------------------- */
bool isVariableLegal(const char * str){
    const char * lchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    const char * mchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789";
    const char * fchars   = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    for(unsigned int i = 0; i < strlen(str); i++){
        const char * allowed_chars = mchars;
        if(i == 0){
            allowed_chars = fchars;
        }else if(i == strlen(str) - 1){
            allowed_chars = lchars;
        }
        bool charfound = false;
        for(unsigned int k = 0; k < strlen(allowed_chars); k++){
            if(str[i] == allowed_chars[k]){
                charfound = true;
                break;
            }
        }
        if(!charfound) return false;
    }
    return true;
}
/* ------------------------------------------------------------------------- */
bool isStringInteger(const char * str){
    const char * lchars = "0123456789";
    const char * mchars = "0123456789";
    const char * fchars   = "+-0123456789";
    for(unsigned int i = 0; i < strlen(str); i++){
        const char * allowed_chars = mchars;
        if(i == 0){
            allowed_chars = fchars;
        }else if(i == strlen(str) - 1){
            allowed_chars = lchars;
        }
        bool charfound = false;
        for(unsigned int k = 0; k < strlen(allowed_chars); k++){
            if(str[i] == allowed_chars[k]){
                charfound = true;
                break;
            }
        }
        if(!charfound) return false;
    }
    return true;
}
/* ------------------------------------------------------------------ */
bool isStringReal(const char * str){
    // strict checking
    const char norepeatchar = '.';
    const char * lchars = "0123456789";
    const char * mchars = ".0123456789";
    const char * fchars   = "+-0123456789";

    int norepeatcharcount = 0;

    for(unsigned int i = 0; i < strlen(str); i++){
        const char * allowed_chars = mchars;
        if(i == 0){
            allowed_chars = fchars;
        }else if(i == strlen(str) - 1){
            allowed_chars = lchars;
        }
        bool charfound = false;
        for(unsigned int k = 0; k < strlen(allowed_chars); k++){
            if(str[i] == allowed_chars[k]){
                if(str[i] == norepeatchar){
                    if(norepeatcharcount > 0) return false;
                    norepeatcharcount++;
                }
                charfound = true;
                break;
            }
        }
        if(!charfound) return false;
    }
    return true;
}
/* ------------------------------------------------------------------------- */
void RemoveConst(const string & name, ParserX & P){
    fatal_stop("Add func body.");
};
/* ------------------------------------------------------------------------- */
void RemoveFun(const string & name, ParserX & P){
    fatal_stop("Add func body.");
}
/* ------------------------------------------------------------------------- */
void forceDefineVar(ParserX & P, const string & sname, Value * new_var){
    // shadows previously defined parameters of the same name, unless it is a constant or function
    if( istokendefinedinparser(P, sname) ){
        // 
        P.RemoveVar(sname);
        P.RemoveConst(sname);
        P.RemoveFunDef(sname); 
    }
    P.DefineVar(sname, new_var );
};
/* ------------------------------------------------------------------------- */
bool isVariableDefined(const string & name, const ParserX & p){
    // Get the map with the variables
    var_maptype variables = p.GetVar();
    //cout << "Number: " << (int)variables.size() << "\n";
    // Get the number of variables 
    var_maptype::const_iterator item = variables.begin();
    // Query the variables
    for (; item!=variables.end(); ++item){
        //cout << "Name: " << item->first << " Address: [0x" << item->second << "]\n";
        if(item->first == name) return true;
    } 
    return false;
};
/* ------------------------------------------------------------------------- */
bool isConstantDefined(const string & name, const ParserX & p){
    val_maptype constants = p.GetConst();
    val_maptype::const_iterator item = constants.begin();
    for( ; item != constants.end(); ++item ){
        if(item ->first == name) return true;
    }
    return false;
};
/* ------------------------------------------------------------------------- */
bool isFunctionDefined(const string & name, const ParserX & p){
    fun_multimap functions = p.GetFunDef();
    fun_multimap::const_iterator item = functions.begin();
    for( ; item != functions.end(); ++item ){
        if( item->first == name ) return true;
    }
    return false;
};
/* ------------------------------------------------------------------------- */
bool isTokenDefined(const string & name, const ParserX & p){
    if(isVariableDefined(name, p)) return true;
    if(isConstantDefined(name, p)) return true;
    if(isFunctionDefined(name, p)) return true;
    return false;
};
/* ------------------------------------------------------------------------- */
// Two functions below are simple implementations of machine independent
// converters between types. Use of the type casting operator in c++
// is usually sufficient, but we include these here for compatiblity with
// sun machines.
char convertdigittochar(const int & digit){
    const char * list = "0123456789";
    if(digit < 0 || digit > 9) return '0';
    return list[digit];
}
/* ------------------------------------------------------------------------- */
string convertint2string(const int & val){
    string dest;
    stdsprintf(dest, "%i", val);
    return dest;
}
/* ------------------------------------------------------------------------- */
// Function takes a const char, counts the number of times it appears
// between the spos and the epos in the string. No bounds checking is
// done, so make sure the epos and spos occur within the string in memory
// for accurate results.
int countChars(const char * str, const char c, int spos, int epos){
    int count = 0;
    for(int i = spos; i <= epos; i++){
        if(str[i] == c) count++;
    }
    return count;
}
// ==========================================================================
// global_flag class
// ==========================================================================
global_flag::global_flag(){
    flag = 0;
}
/* ------------------------------------------------------------------------- */
const sig_atomic_t global_flag::read() const{
    return this->flag;
}
/* ------------------------------------------------------------------------- */
void global_flag::set(sig_atomic_t val){
    this->flag = val;
};
/* ------------------------------------------------------------------------- */
void global_flag::toggle(){
    this->flag = 1;
};
/* ------------------------------------------------------------------------- */
void global_flag::reset(){
    this->flag = 0;
};
/* ------------------------------------------------------------------------- */
global_flag & gbl_SIG_INT(){
    static global_flag flag;
    return flag;
};
/* ------------------------------------------------------------------------- */
void check_for_signals(){
    if( gbl_SIG_INT().read() != 0 ){
        throw cgcmexception("INTERRUPT", SIG_INT_EXCEPTION_NUMBER);
    }
};
/* ------------------------------------------------------------------------- */
bool is_exception_SIG_INT(const cgcmexception & ex){
    return ex.id() == SIG_INT_EXCEPTION_NUMBER;
};
#endif
